#pragma once
#include <libmalloc.h>
#include <metalc/base/mlayer.h>

#include <pthreadalt/pthreadalt_init.h>
DEF_PTHREADALT_INIT
/* 先定义胶水层 */
DEF_MLAYER_BASIC(mallocapi, -1, 0)

#define MREQ_SETALLOC(req, size, align, tls)		mreq_setalloc(req, size, align)
static inline void mallocapi_pinit(const mlfunc_t *next)
{
	PARAM_USED(next);
}

static inline void mallocapi_tinit(const mlfunc_t *next)
{
	PARAM_USED(next);
}
/* 初始化流程先procinit -> 不能调用任何可能malloc的接口 -> 初始化必要的内存分配 */
DECL_MLAYER_COMPFUNC(mallocapi)
SAI void *mallocapi_alloc(mreq_t *req, const mlfunc_t *next)
{
	return next->lalloc(req);
}

SAI bool_t mallocapi_free(mreq_t *req, const mlfunc_t *next)
{
	return next->lfree(req);
}

SAI size_t mallocapi_sizeof(mreq_t *req, const mlfunc_t *next)
{
	return next->lsizeof(req);
}

SAI size_t ptr_get_usable_size(mreq_t *req, void *ptr){
	req->ptr = ptr;
	return mallocapi_sizeof_comp(req);
}

SNI void extlib_initialize(){
	// INFO("pthreadalt_custom_constructor\n");
	proc_initializer(); 
	cflow_init();
	reg_thread_destructor();
}

HOT SIN void *__malloc_ex(size_t size, size_t alignment){
	PARAM_USED(alignment);
	mreq_t req;
	
	// MREQ_SETALLOC(&req, size, alignment, mtls_get_init());
	mreq_setalloc(&req, size, 0);
	ASSERT(req.align == 0);
	///fprintf(stderr, "m size %lu\n", req.ptr, size);
	void *ret = mallocapi_alloc_comp(&req);
	// ASSERT(ret);
	return ret;
}

HOT SIN void __free_ex(void *ptr)
{
	mreq_t req;
	// mreq_setfree(&req, ptr, usable_size);
	// mallocapi_free_comp(&req);
	
	req.cls = 0;
	ptr_get_usable_size(&req, ptr);
	mreq_setfree(&req, ptr, req.size);
	mallocapi_free_comp(&req);
}


__attribute__ ((__nothrow__ , __malloc__ , __alloc_size__ (1) )) 
HOT void* malloc(size_t size){

	/* TODO: 这里可以不需要? */
	if (UNLIKELY(!size))
		return NULL_PTR;

#ifdef METALC_DYNLIB
	/* 在这里初始化 */
	extern cid_t __max_threads;
	if (UNLIKELY(__max_threads == 0)){
		/* 执行完后max_threads一定不等于1 */
		extlib_initialize();
		INFO("pthreadalt_custom_constructor %u\n", __max_threads);
	}
	
#endif
	return __malloc_ex(size, 0);
}

__attribute__ ((__nothrow__)) 
HOT void free(void *ptr){
	mreq_t req;
	word_t blk_size;

	if (UNLIKELY(!ptr))
		return;
	
	// ptr_get_usable_size(&req, ptr);
	// mreq_setfree(&req, ptr, req.size);
	// mallocapi_free_comp(&req);
	__free_ex(ptr);
}

#include <string.h>
__attribute__ ((__nothrow__ , __malloc__ , __alloc_size__ (1, 2) )) 
void* calloc(size_t unit_size, size_t nr){
	void *ret;
	if (UNLIKELY(unit_size == 0))
		return NULL_PTR;
#ifdef METALC_DYNLIB
	/* 在这里初始化 */
	extern cid_t __max_threads;
	if (UNLIKELY(__max_threads == 0)){
		/* 执行完后max_threads一定不等于1 */
		extlib_initialize();
		INFO("pthreadalt_custom_constructor %u\n", __max_threads);
	}
	
#endif
	/* 试试改成malloc省空间? */
	ret = __malloc_ex(unit_size * nr, 0);


	// ret = malloc(unit_size * nr);
	if (LIKELY(ret))
		memset(ret, 0, unit_size * nr);
	return ret;
}
/* 释放 */
__attribute__ ((__nothrow__ , __malloc__ , __alloc_size__ (2) )) 
void* realloc(void *ptr, size_t size){
	// 先alloc再free
	if (UNLIKELY(!ptr)){
		if (LIKELY(size != 0))
			return __malloc_ex(size, 0);
		// /* size == 0且 ptr为空 */
		return NULL_PTR;
		// return malloc(size);
	}

	// if (UNLIKELY(size <= old_size))
	// 	return ptr;
	void *new_ptr = NULL_PTR;
	if (LIKELY(size != 0)){
		/* size 不等0才申请 */
		
		mreq_t req;
		/* 先申请 */
		size_t old_size = ptr_get_usable_size(&req, ptr);
		/* FIXME: 原本的大小已经满足可直接返回，似乎可以提升REDIS性能? */
		if (UNLIKELY(size <= old_size))
			return ptr;

		size_t cpy_size = size <= old_size ? size : old_size;
		new_ptr = __malloc_ex(size, 0);
		if (LIKELY(new_ptr)){
			memcpy(new_ptr, ptr, cpy_size);
		}
	}

	// mreq_setfree(&req, ptr, req.size);
	// mallocapi_free_comp(&req);
	
	/* 释放ptr */
	// free(ptr);
	__free_ex(ptr);

	return new_ptr;
}



/* 连接 */
#ifndef NOT_REPLACE_USABLE_SIZE
__attribute__ ((__nothrow__)) 
size_t malloc_usable_size (void *ptr){
	mreq_t req;
	return (size_t)ptr_get_usable_size(&req, ptr);
}
#endif



SIN void *__memalign_ex(size_t alignment, size_t size)
{
	// mreq_t req;
	// word_t req_size;

	/* 使用对齐申请 */
	
	// if (!is_powerof2(alignment)) {
	// 	errno = EINVAL;
	// 	return NULL_PTR;
	// }

	// return __malloc_ex(size, alignment);

	/* 改用这种方式是为了优化开销 */
	mreq_t req;
	mreq_setalloc(&req, size, alignment);
	void *ret = mallocapi_alloc_comp(&req);
	return ret;
}

#include <errno.h>

/* https://man7.org/linux/man-pages/man3/posix_memalign.3.html
	对于posix_memalign, memalign和aligned_alloc三个接口而言
	其约束为
	posix_memalign: size为0时 *mem_ptr可以是空指针或者任意内存指针
	对齐值alignment必须是2的幂次方且是sizeof(void *)的整数倍
	memalign: alignment必须是2的幂次方
	aligned_alloc: 与memalign相同，同时size必须是alignment的整数倍

*/
__attribute__ ((__nothrow__)) 
int posix_memalign(void **mem_ptr, size_t alignment, size_t size){
	mreq_t req;
	if (UNLIKELY(size == 0)){
		/* man: If size is 0, then the value placed in *memptr is either NULL or a unique pointer value */
		*mem_ptr = NULL_PTR;
		return 0; 
	}
	/* 对齐 */
	if (
		((alignment % sizeof(size_t)) != 0) ||
		((alignment & (alignment - 1)) != 0) || (alignment == 0) || !is_powerof2(alignment))
	{
		return EINVAL;
	}

	void *p = __memalign_ex(alignment, size);

	if (p == NULL_PTR)
	{
		return ENOMEM;
	}
	*mem_ptr = p;
	return 0;
}

__attribute__ ((__nothrow__ , __malloc__ , __alloc_size__ (2) )) 
void* memalign(size_t alignment, size_t size){
	if (UNLIKELY(size == 0)){
		return NULL_PTR; 
	}
	if ((alignment == 0) || (alignment == (size_t)(-1)) || !is_powerof2(alignment))
	{
		/* 必须是2幂次方 */
		errno = EINVAL;
		return NULL_PTR;
	}

	if ((size + alignment) < size)
	{
		errno = ENOMEM;
		return NULL;
	}

	return __memalign_ex(alignment, size);
}

__attribute__((__nothrow__, __malloc__, __alloc_size__(2)))
void *aligned_alloc(size_t alignment, size_t size){
	if (UNLIKELY(size == 0)){
		return NULL_PTR; 
	}
	if ((alignment == 0) || (alignment == (size_t)(-1)))
	{
		errno = EINVAL;
		return NULL_PTR;
	}
	/* 必须是2幂次方，同时size对齐 */
	if (!is_powerof2(alignment) || !is_aligned(size, alignment)) {
		errno = EINVAL;
		return NULL_PTR;
	}

	if ((size + alignment) < size)
	{
		errno = ENOMEM;
		return NULL;
	}

	return __memalign_ex(alignment, size);
}

__attribute__ ((__nothrow__ , __malloc__ , __alloc_size__ (1) )) 
void* valloc(size_t size){
	if (UNLIKELY(!size)) return NULL_PTR;
	return __memalign_ex(HPAGE_SIZE(0), size);
}

__attribute__ ((__nothrow__ , __malloc__)) 
void* pvalloc(size_t size){
	/* 巨页 */
	if (UNLIKELY(!size)) return NULL_PTR;
	return __memalign_ex(HPAGE_SIZE(1), size);
}

#include <malloc.h>
__attribute__ ((__nothrow__))
int mallopt(int param, int value) 
{
	PARAM_USED(param, value);
	return 1;
}

__attribute__ ((__nothrow__))
struct mallinfo mallinfo()
{
	struct mallinfo m;
	memset(&m, 0, sizeof(struct mallinfo));
	return m;
}
__attribute__ ((__nothrow__))
void malloc_stats(void){
	return;
}
__attribute__ ((__nothrow__))
int malloc_info(int options, FILE *stream){
	PARAM_USED(options, stream);
	return 0;
}
__attribute__ ((__nothrow__))
int malloc_trim(size_t pad) {
	/* 尝试触发整理 */
	PARAM_USED(pad);
	return 0;
}
__attribute__ ((__nothrow__))
void *malloc_get_state(void) {
	errno = ENOSYS;
	return NULL;
}
__attribute__ ((__nothrow__))
int malloc_set_state(void *state) {
	PARAM_USED(state);
	return -2;
}

/* 替换C库 */
__attribute__ ((__nothrow__))
void* __libc_malloc(size_t size){
	return malloc(size);
}
__attribute__ ((__nothrow__)) 
void __libc_free(void* ptr) {
	return free(ptr);
}
__attribute__ ((__nothrow__)) void* __libc_realloc(void* ptr, size_t size){
	return realloc(ptr, size);
}
__attribute__ ((__nothrow__))
void* __libc_calloc(size_t n, size_t size) {
	return __libc_calloc(n, size);
}
__attribute__ ((__nothrow__))
void __libc_cfree(void* ptr){
	free(ptr);
}
__attribute__ ((__nothrow__)) 
void* __libc_memalign(size_t align, size_t s){
	return memalign(align, s);
}
__attribute__ ((__nothrow__)) void* __libc_valloc(size_t size){
	return valloc(size);
}

__attribute__ ((__nothrow__))
void* __libc_pvalloc(size_t size){
	return pvalloc(size);
}

__attribute__ ((__nothrow__))
int __posix_memalign(void** r, size_t a, size_t s){
	return posix_memalign(r, a, s);
}